package cn.juque.workflow.converter;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.juque.common.utils.SqlHelper;
import cn.juque.systemservice.api.dto.employee.EmployeeInfoDetailDTO;
import cn.juque.workflow.api.dto.taskinfo.CandidateUserDTO;
import cn.juque.workflow.api.dto.taskinfo.ProcessInstanceDetailDTO;
import cn.juque.workflow.api.dto.taskinfo.TaskInfoListDTO;
import cn.juque.workflow.api.enums.VariableEnum;
import cn.juque.workflow.bo.businesstask.BusinessTaskDetailBO;
import cn.juque.workflow.domain.ProcessTaskDO;
import cn.juque.workflow.helper.EmployeeInfoHelper;
import org.camunda.bpm.engine.HistoryService;
import org.camunda.bpm.engine.TaskService;
import org.camunda.bpm.engine.history.HistoricTaskInstance;
import org.camunda.bpm.engine.history.HistoricTaskInstanceQuery;
import org.camunda.bpm.engine.history.HistoricVariableInstance;
import org.camunda.bpm.engine.task.Task;
import org.camunda.bpm.engine.task.TaskQuery;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author juque
 * @version 1.0.0
 * <ul>
 *     <li>ProcessTaskDoConverter</li>
 * </ul>
 * @date 2023-01-30 15:12:23
 **/
public class ProcessTaskConverter {

    private ProcessTaskConverter() {
    }

    /**
     * 转换查询条件
     *
     * @param taskQuery     TaskQuery
     * @param processTaskDO ProcessTaskDO
     */
    public static void toProcessTaskDO(TaskQuery taskQuery, ProcessTaskDO processTaskDO) {
        if (CharSequenceUtil.isNotEmpty(processTaskDO.getProcessInstanceId())) {
            taskQuery.processInstanceId(processTaskDO.getProcessInstanceId());
        }
        if (CharSequenceUtil.isNotEmpty(processTaskDO.getTitle())) {
            taskQuery.processVariableValueLike(VariableEnum.TITLE.getValue(), SqlHelper.allLike(processTaskDO.getTitle()));
        }
        if (CharSequenceUtil.isNotEmpty(processTaskDO.getInitiator())) {
            taskQuery.processVariableValueEquals(VariableEnum.INITIATOR.getValue(), processTaskDO.getInitiator());
        }
        if (CharSequenceUtil.isNotEmpty(processTaskDO.getTaskAssignee())) {
            taskQuery.taskAssignee(processTaskDO.getTaskAssignee());
        }
        if (CharSequenceUtil.isNotEmpty(processTaskDO.getCandidateUser())) {
            taskQuery.taskCandidateUser(processTaskDO.getCandidateUser());
        }
        if (null != processTaskDO.getCreateTimeStart()) {
            taskQuery.taskCreatedAfter(processTaskDO.getCreateTimeStart());
        }
        if (null != processTaskDO.getCreateTimeEnd()) {
            taskQuery.taskCreatedBefore(processTaskDO.getCreateTimeEnd());
        }
    }

    /**
     * 转换查询条件
     *
     * @param taskQuery     HistoricTaskInstanceQuery
     * @param processTaskDO ProcessTaskDO
     */
    public static void toProcessTaskDO(HistoricTaskInstanceQuery taskQuery, ProcessTaskDO processTaskDO) {
        if (CharSequenceUtil.isNotEmpty(processTaskDO.getTitle())) {
            taskQuery.processVariableValueLike(VariableEnum.TITLE.getValue(), processTaskDO.getTitle());
        }
        if (null != processTaskDO.getCreateTimeStart()) {
            taskQuery.startedAfter(processTaskDO.getCreateTimeStart());
        }
        if (null != processTaskDO.getCreateTimeEnd()) {
            taskQuery.startedBefore(processTaskDO.getCreateTimeEnd());
        }
    }

    public static TaskInfoListDTO toTaskInfoListDTO(Task task) {
        if (null == task) {
            return null;
        }
        TaskInfoListDTO dto = new TaskInfoListDTO();
        dto.setId(task.getId());
        dto.setAssignee(task.getAssignee());
        dto.setProcessInstanceId(task.getProcessInstanceId());
        dto.setProcessDefinitionId(task.getProcessDefinitionId());
        dto.setParentTaskId(task.getParentTaskId());
        dto.setDueDate(task.getDueDate());
        dto.setCreateTime(task.getCreateTime());
        return dto;
    }

    public static List<TaskInfoListDTO> toTaskInfoListDTOList(List<Task> taskList) {
        if (CollUtil.isEmpty(taskList)) {
            return CollUtil.newArrayList();
        }
        TaskService taskService = SpringUtil.getBean(TaskService.class);
        List<TaskInfoListDTO> list = taskList.stream()
                .map(m -> {
                    TaskInfoListDTO dto = ProcessTaskConverter.toTaskInfoListDTO(m);
                    Map<String, Object> variables = taskService
                            .getVariables(
                                    m.getId(),
                                    CollUtil.newArrayList(VariableEnum.TITLE.getValue(),
                                            VariableEnum.INITIATOR.getValue()));
                    dto.setTitle(variables.getOrDefault(VariableEnum.TITLE.getValue(), CharSequenceUtil.EMPTY).toString());
                    dto.setInitiator(variables.getOrDefault(VariableEnum.INITIATOR.getValue(), CharSequenceUtil.EMPTY).toString());
                    return dto;
                }).collect(Collectors.toList());

        List<String> initiatorList = list.stream().map(TaskInfoListDTO::getInitiator)
                .filter(CharSequenceUtil::isNotEmpty).collect(Collectors.toList());
        EmployeeInfoHelper employeeInfoHelper = SpringUtil.getBean(EmployeeInfoHelper.class);
        List<EmployeeInfoDetailDTO> employeeDetailList = employeeInfoHelper.listEmployeeByUserId(initiatorList);
        Map<String, EmployeeInfoDetailDTO> employeeMap = employeeDetailList.stream().collect(Collectors.toMap(EmployeeInfoDetailDTO::getUserId, t -> t, (k1, k2) -> k2));
        list.forEach(m -> m.setInitiatorName(employeeMap.getOrDefault(m.getInitiator(), new EmployeeInfoDetailDTO()).getEmployeeName()));
        return list;
    }

    public static TaskInfoListDTO toTaskInfoListDtoByHistory(HistoricTaskInstance historicTaskInstance) {
        if (null == historicTaskInstance) {
            return null;
        }
        TaskInfoListDTO dto = new TaskInfoListDTO();
        dto.setId(historicTaskInstance.getId());
        dto.setAssignee(historicTaskInstance.getAssignee());
        dto.setProcessInstanceId(historicTaskInstance.getProcessInstanceId());
        dto.setProcessDefinitionId(historicTaskInstance.getProcessDefinitionId());
        dto.setParentTaskId(historicTaskInstance.getParentTaskId());
        dto.setDueDate(historicTaskInstance.getDueDate());
        dto.setStartTime(historicTaskInstance.getStartTime());
        dto.setEndTime(historicTaskInstance.getEndTime());
        return dto;
    }

    public static List<TaskInfoListDTO> toTaskInfoListDtoListByHistory(List<HistoricTaskInstance> list) {
        if (CollUtil.isEmpty(list)) {
            return CollUtil.newArrayList();
        }
        HistoryService historyService = SpringUtil.getBean(HistoryService.class);
        List<TaskInfoListDTO> dtoList = list.stream().map(m -> {
            TaskInfoListDTO dto = ProcessTaskConverter.toTaskInfoListDtoByHistory(m);
            List<HistoricVariableInstance> variableInstanceList = historyService.createHistoricVariableInstanceQuery()
                    .processInstanceId(m.getProcessInstanceId())
                    .variableNameIn(VariableEnum.TITLE.getValue(), VariableEnum.INITIATOR.getValue()).list();
            Map<String, Object> variables = variableInstanceList.stream().collect(Collectors.toMap(HistoricVariableInstance::getName, HistoricVariableInstance::getValue, (k1, k2) -> k1));
            dto.setTitle(variables.getOrDefault(VariableEnum.TITLE.getValue(), CharSequenceUtil.EMPTY).toString());
            dto.setInitiator(variables.getOrDefault(VariableEnum.INITIATOR.getValue(), CharSequenceUtil.EMPTY).toString());
            return dto;
        }).collect(Collectors.toList());
        List<String> initiatorList = dtoList.stream().map(TaskInfoListDTO::getInitiator)
                .filter(CharSequenceUtil::isNotEmpty).collect(Collectors.toList());
        EmployeeInfoHelper employeeInfoHelper = SpringUtil.getBean(EmployeeInfoHelper.class);
        List<EmployeeInfoDetailDTO> employeeDetailList = employeeInfoHelper.listEmployeeByUserId(initiatorList);
        Map<String, EmployeeInfoDetailDTO> employeeMap = employeeDetailList.stream().collect(Collectors.toMap(EmployeeInfoDetailDTO::getUserId, t -> t, (k1, k2) -> k2));
        dtoList.forEach(f -> f.setInitiatorName(employeeMap.getOrDefault(f.getInitiator(), new EmployeeInfoDetailDTO()).getEmployeeName()));
        return dtoList;
    }

    public static ProcessInstanceDetailDTO toProcessInstanceDetailDTO(BusinessTaskDetailBO<?> businessTaskDetailBO) {
        if (null == businessTaskDetailBO) {
            return new ProcessInstanceDetailDTO();
        }
        ProcessInstanceDetailDTO dto = new ProcessInstanceDetailDTO();
        dto.setProcessInstanceId(businessTaskDetailBO.getProcessInstanceId());
        dto.setEntity(businessTaskDetailBO.getEntity());
        List<CandidateUserDTO> userList = BeanUtil.copyToList(businessTaskDetailBO.getCandidateUserList(), CandidateUserDTO.class);
        dto.setCandidateUserList(userList);
        return dto;
    }
}
